package com.ronan.imserver.handler;

import com.ronan.common.pojo.RimUmsInfo;
import com.google.protobuf.MessageLite;
import com.ronan.common.constant.Constants;
import com.ronan.common.protocol.RIMProtocol;
import com.ronan.common.utils.SessionManager;
import com.ronan.imserver.processor.RIMProcessor;
import com.ronan.imserver.processor.RIMProcessorManager;
import com.ronan.imserver.service.RIMService;
import com.ronan.imserver.utils.SpringBeanFactory;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

/**
 * FileName    : com.ronan.imserver.handler
 * Description :
 *
 * @author : ronan
 * @version : 1.0
 * Create Date : 2021/2/26 10:18
 **/
@Slf4j
@ChannelHandler.Sharable
public class RIMBizHandler extends SimpleChannelInboundHandler<RIMProtocol> {

    /**
     * 定义客户端没有收到服务端的pong消息的最大次数
     */
    private static final int MAX_UN_REC_PING_TIMES = 3;

    /**
     * 失败计数器：未收到client端发送的ping请求
     * 读空闲次数
     */
    private int readIdleTimes = 0;


    /**
     * 离线,取消绑定
     *
     * @param ctx 上下文
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.warn("用户:[{}] 断开连接!!", ctx.channel().remoteAddress());
        RIMService rimService = SpringBeanFactory.getBean(RIMService.class);
        RimUmsInfo ums = SessionManager.getUmsInfo(ctx.channel());
        if (null != ums) {
            log.warn("用户:[{}] 离线!!", ums.getAccid());
            // 清除本地数据、redis的路由信息、登录状态
            rimService.userOffline(ums, ctx.channel());
            ctx.channel().close();
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.warn("用户:[{}] 连接!!", ctx.channel().remoteAddress());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RIMProtocol protocol) throws Exception {

        // 消息体
        MessageLite body = protocol.getBody();
        // 根据body选择对应的处理器
        RIMProcessor processor = RIMProcessorManager.chooseProcessor(body);

        // 当其他消息(游戏...)时交给处理器
        // command = 1 登录
        // command = 2 心跳
        // 当获取到业务数据时 command = 4
        if (Constants.MsgConstant.MESSAGE != protocol.getHeader().getCommand() && null != processor) {
            processor.process(body, ctx.channel());
        }

        // 当是推送消息时的处理 command = 3
        if (Constants.MsgConstant.MESSAGE == protocol.getHeader().getCommand()) {
            // RIMServer rimServer = SpringBeanFactory.getBean(RIMServer.class);
            // Message msg = (Message) body;
            // // 根据消息接收者id获取消息接收者的channel
            // Channel channel = SessionManager.get(msg.getTo());
            // // 消息推送
            // rimServer.sendMsg(protocol,channel);
            ctx.writeAndFlush(protocol);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

        IdleStateEvent event = (IdleStateEvent) evt;
        String eventType = null;
        switch (event.state()) {
            case READER_IDLE:
                eventType = "读空闲";
                readIdleTimes++;
                break;
            case WRITER_IDLE:
                eventType = "写空闲";
                break;
            case ALL_IDLE:
                eventType = "读写空闲";
                break;
            default:
                break;
        }
        log.info("用户：[{}]，超时类型：[{}]", ctx.channel().remoteAddress(), eventType);
        if (readIdleTimes >= MAX_UN_REC_PING_TIMES) {
            // 连续超过3次未收到client的ping消息，那么关闭该通道，等待client重连
            log.warn("服务端读空闲超过3次,关闭连接,等待客户端重连");
            ctx.channel().close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error(cause.getMessage(), cause);
        ctx.close();
    }
}
